package 线程通信;

import java.util.Random;

public class 阻塞队列 {

    //循环数组：存取元素
    private int[] elements;
    //有效负荷
    private int size;
    //放元素的索引
    private int putIndex;
    //取元素的索引
    private int takeIndex;
    /**
     * @param capacity 容量
     */
    public 阻塞队列(int capacity){
        elements = new int[capacity];
    }

    /**
     * 放元素到阻塞队列：需要保证线程安全，如果队列满了，需要等待
     * @param element
     */
    public synchronized void put(int element) throws InterruptedException {
        //如果满了，就等
        while(elements.length == size){
            wait();
        }
        //如果不满，就放
        elements[putIndex] = element;
        //放的索引往后移动一位（取模是在最后一个位置就往首位移动）
        putIndex = (putIndex+1) % elements.length;
        //有效负荷+1
        size++;
        //通知wait等待的线程
        notifyAll();
    }

    /**
     * 取元素：需要保证线程安全，如果队列是空，需要等待
     * @return
     */
    public synchronized int take() throws InterruptedException {
        //如果是空，就等
        while(size == 0){
            wait();
        }
        //如果不空，就取
        int element = elements[takeIndex];
        //取的索引往后移动一位（取模是在最后一个位置就往首位移动）
        takeIndex = (takeIndex+1) % elements.length;
        //有效负荷-1
        size--;
        //通知wait等待的线程
        notifyAll();
        return element;
    }


    public static void main(String[] args) throws InterruptedException {
        阻塞队列 queue = new 阻塞队列(20);
        new Thread(new Runnable() {
            @Override
            public void run() {
                //模拟消费者
                while (true){
                    try {
                        int e = queue.take();
                        System.out.println("取到的数字："+e);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
        Thread.sleep(100);
        new Thread(new Runnable() {
            @Override
            public void run() {
                //模拟生产者
                while (true){
                    try {
                        queue.put(new Random().nextInt());
                        Thread.sleep(1000);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();

    }
}
